import { BrickPartyBlock, BlockAnimationState, GameEventData, GameEventType } from "../bean/GameBean";

/**
 * 方块动画管理器
 * 负责管理9x9格子的方块动画效果
 */
export class BlockAnimationManager {
    private static instance: BlockAnimationManager = null;
    
    // 9x9方块网格 (左下角为(0,0))
    private blockGrid: cc.Node[][] = [];
    private blockAnimationStates: string[][] = [];
    private blockAnimationTimers: number[][] = [];
    
    // 当前方块皮肤名称，用于在setToSetupPose后重新应用
    private currentSkinName: string = 'zhuankuai1';
    
    // 动画配置
    private readonly GRID_SIZE = 9;
    // 动画持续时间配置（毫秒）- 匹配服务器阶段时长
    private readonly ANIMATION_DURATIONS = {
        [BlockAnimationState.SHAKE]: 1800,  // 抖动动画 1.8秒 (避免红色状态残留)
        [BlockAnimationState.FALL]: 2000,   // 下落动画 2秒 (匹配服务器40帧)
        [BlockAnimationState.RISE]: 1000,   // 上升动画 1秒 (匹配服务器20帧)
        [BlockAnimationState.NONE]: 0       // 默认状态无动画
    };
    
    // 方块父节点
    private blockParent: cc.Node = null;
    
    // 待执行的动画任务队列 - 用于取消已调度但尚未执行的动画
    private pendingAnimationTasks: Map<string, number> = new Map();
    
    // 方块原始状态保存 - 用于动画后恢复
    private originalBlockStates: Map<string, {position: cc.Vec3, scale: cc.Vec3, opacity: number}> = new Map();
    
    // 当前动画状态管理
    private currentAnimationPhase: string = 'idle';
    private animationStartTime: number = 0;
    private totalAnimationDuration: number = 0;
    
    public static getInstance(): BlockAnimationManager {
        if (!BlockAnimationManager.instance) {
            BlockAnimationManager.instance = new BlockAnimationManager();
        }
        return BlockAnimationManager.instance;
    }
    
    /**
     * 初始化方块动画管理器
     * @param blockParent 包含现有方块的父节点
     */
    public initialize(blockParent: cc.Node): void {
        this.blockParent = blockParent;
        this.initializeGridFromExistingBlocks();
    }
    
    /**
     * 从现有方块初始化9x9方块网格
     */
    private initializeGridFromExistingBlocks(): void {
        if (!this.blockParent) {
            console.error("方块父节点未设置");
            return;
        }
        
        // 初始化网格数组
        for (let x = 0; x < this.GRID_SIZE; x++) {
            this.blockGrid[x] = [];
            this.blockAnimationStates[x] = [];
            this.blockAnimationTimers[x] = [];
            
            for (let y = 0; y < this.GRID_SIZE; y++) {
                this.blockGrid[x][y] = null;
                this.blockAnimationStates[x][y] = BlockAnimationState.NONE;
                this.blockAnimationTimers[x][y] = 0;
            }
        }
        
        // 查找现有的方块节点并分配到网格中
        this.mapExistingBlocksToGrid();
        
       
    }
    
    /**
     * 将现有方块节点映射到网格中
     */
    private mapExistingBlocksToGrid(): void {
        const children = this.blockParent.children;
       
        
        for (const child of children) {
            // 尝试从节点位置推断网格坐标
            const gridPos = this.worldToGridPosition(child.getPosition());
            
            if (this.isValidGridPosition(gridPos.x, gridPos.y)) {
                this.blockGrid[gridPos.x][gridPos.y] = child;
                // 设置节点名称便于调试
                child.name = `Block_${gridPos.x}_${gridPos.y}`;
                // 初始化为默认状态
                this.setBlockAnimationState(child, BlockAnimationState.NONE);
                
            } else {
                
            }
        }
        
        // 检查是否有缺失的方块
        this.checkMissingBlocks();
    }
    
    /**
     * 网格坐标转世界坐标
     * 坐标系：左下角(0,0)，左上角(0,8)，右上角(8,8)
     * 实际格子位置：左上(-320,320)，右上(320,320)，左下(-320,-320)，右下(320,-320)
     */
    private gridToWorldPosition(gridX: number, gridY: number): cc.Vec2 {
        // 格子间距：总宽度640像素 ÷ 8个间隔 = 80像素
        const CELL_SPACING = 80;
        const GRID_OFFSET_X = -320; // 棋盘左下角X坐标
        const GRID_OFFSET_Y = -320; // 棋盘左下角Y坐标
        
        // X轴：从左到右 (0-8)
        // Y轴：从下到上 (0-8)
        const worldX = GRID_OFFSET_X + gridX * CELL_SPACING;
        const worldY = GRID_OFFSET_Y + gridY * CELL_SPACING;
        
        return cc.v2(worldX, worldY);
    }
    
    /**
     * 世界坐标转网格坐标
     * 坐标系：左下角(0,0)，左上角(0,8)，右上角(8,8)
     * 实际格子位置：左上(-320,320)，右上(320,320)，左下(-320,-320)，右下(320,-320)
     */
    private worldToGridPosition(worldPos: cc.Vec2): cc.Vec2 {
        // 格子间距：总宽度640像素 ÷ 8个间隔 = 80像素
        const CELL_SPACING = 80;
        const GRID_OFFSET_X = -320; // 棋盘左下角X坐标
        const GRID_OFFSET_Y = -320; // 棋盘左下角Y坐标
        
        // X轴：从左到右 (0-8)
        // Y轴：从下到上 (0-8)
        const gridX = Math.round((worldPos.x - GRID_OFFSET_X) / CELL_SPACING);
        const gridY = Math.round((worldPos.y - GRID_OFFSET_Y) / CELL_SPACING);
        
        return cc.v2(gridX, gridY);
    }
    
    /**
     * 检查是否为有效的网格位置
     */
    private isValidGridPosition(gridX: number, gridY: number): boolean {
        return gridX >= 0 && gridX < this.GRID_SIZE && gridY >= 0 && gridY < this.GRID_SIZE;
    }
    
    /**
     * 刷新方块网格引用 - 重新扫描父节点中的方块
     */
    private refreshBlockGridReferences(): void {
        if (!this.blockParent || !cc.isValid(this.blockParent)) {
            return;
        }
        
        // 清空当前网格中失效的引用
        for (let x = 0; x < this.GRID_SIZE; x++) {
            for (let y = 0; y < this.GRID_SIZE; y++) {
                const blockNode = this.blockGrid[x][y];
                if (blockNode && (!cc.isValid(blockNode) || !blockNode.parent)) {
                    
                    this.blockGrid[x][y] = null;
                }
            }
        }
        
        // 重新扫描父节点中的方块
        const children = this.blockParent.children;
        for (const child of children) {
            if (!cc.isValid(child)) continue;
            
            const gridPos = this.worldToGridPosition(child.getPosition());
            if (this.isValidGridPosition(gridPos.x, gridPos.y)) {
                // 只有当前位置为空时才更新引用，避免覆盖有效的引用
                if (!this.blockGrid[gridPos.x][gridPos.y]) {
                    this.blockGrid[gridPos.x][gridPos.y] = child;
                    child.name = `Block_${gridPos.x}_${gridPos.y}`;
                }
            }
        }
    }
    
    /**
     * 取消所有待执行的动画任务
     */
    private cancelAllPendingAnimations(): void {
        this.pendingAnimationTasks.forEach((timeoutId, taskKey) => {
            clearTimeout(timeoutId);
        });
        this.pendingAnimationTasks.clear();
        
    }
    
    /**
     * 取消指定位置的待执行动画任务
     */
    private cancelPendingAnimationsForPosition(gridX: number, gridY: number): void {
        const tasksToCancel: string[] = [];
        this.pendingAnimationTasks.forEach((timeoutId, taskKey) => {
            if (taskKey.includes(`${gridX}-${gridY}`)) {
                clearTimeout(timeoutId);
                tasksToCancel.push(taskKey);
            }
        });
        
        tasksToCancel.forEach(taskKey => {
            this.pendingAnimationTasks.delete(taskKey);
        });
        
    }
    
    /**
     * 检查缺失的方块并报告
     */
    private checkMissingBlocks(): void {
        const missingBlocks: string[] = [];
        let foundBlocks = 0;
        
        for (let x = 0; x < this.GRID_SIZE; x++) {
            for (let y = 0; y < this.GRID_SIZE; y++) {
                if (this.blockGrid[x][y]) {
                    foundBlocks++;
                } else {
                    missingBlocks.push(`(${x},${y})`);
                }
            }
        }
        
        
        if (missingBlocks.length > 0) {
            console.warn(`缺失方块位置: ${missingBlocks.join(', ')}`);
        }
    }
    
    /**
     * 处理游戏事件，触发相应的方块动画
     */
    public handleGameEvent(eventData: GameEventData): void {
       
        
        // 取消之前的动画任务
        this.cancelAllPendingAnimations();
        
        // 保存动画开始时间和总时长
        this.animationStartTime = Date.now();
        this.totalAnimationDuration = eventData.countDown || 2000; // 使用服务器提供的倒计时
        
        
        switch (eventData.eventType) {
            case GameEventType.SHAKING:
                this.handleTimedShakingEvent(eventData);
                break;
            case GameEventType.FALLING:
                this.handleTimedFallingEvent(eventData);
                break;
            case GameEventType.RESTORING:
                this.handleTimedRestoringEvent(eventData);
                break;
            case GameEventType.ENDING:
                // 游戏结束：立即停止所有动画并恢复可见，避免方块长期隐藏在“等待补齐”的状态
                this.stopAllAnimations();
                this.currentAnimationPhase = 'idle';
                break;
            default:
               
                break;
        }
    }
    
    /**
     * 处理定时抖动事件 - 在指定时间内完成所有抖动动画
     */
    private handleTimedShakingEvent(eventData: GameEventData): void {
        if (!eventData.blocks || eventData.blocks.length === 0) {
            console.warn("抖动事件没有方块数据");
            return;
        }
        
        this.currentAnimationPhase = 'shaking';
        
        // 保存所有相关方块的原始状态
        this.saveOriginalBlockStates(eventData.blocks);
        
        // 抖动动画：所有方块同时播放，无延迟
        const playSequence = this.generateShakeAnimationSequence(eventData.blocks);
        
       
        
        // 播放抖动动画序列
        this.playTimedAnimationSequence(playSequence, BlockAnimationState.SHAKE, () => {
            
            // 强制恢复所有抖动方块的原始状态，避免红色状态残留
            this.forceRestoreShakeBlocks(eventData.blocks);
            this.currentAnimationPhase = 'idle';
        });
    }
    
    /**
     * 处理定时掉落事件 - 2秒内完成掉落，单个动画0.5秒，然后隐藏等待
     */
    private handleTimedFallingEvent(eventData: GameEventData): void {
       
        
        if (!eventData.blocks || eventData.blocks.length === 0) {
            console.warn("掉落事件没有方块数据");
            return;
        }
        
        
        this.currentAnimationPhase = 'falling';
        
        // 保存原始状态
        this.saveOriginalBlockStates(eventData.blocks);
        
        // 掉落动画：分三批次播放，间隔0.1-0.3秒
        const playSequence = this.generateBatchedAnimationSequence(eventData.blocks, eventData.randomSeed);
        
       
        
        // 播放掉落动画序列
        this.playFallAnimationSequence(playSequence, () => {
            // 掉落动画完成后进入等待补齐阶段
            this.currentAnimationPhase = 'waiting_for_restore';

            // 兜底：如果在一定时间内没有收到补齐事件(RESTORING)，则强制恢复原状，避免方块长期隐藏
            const fallbackDelay = Math.max(this.totalAnimationDuration || 2000, 2000) + 500; // 动画总时长后再等待0.5s
            const fallbackKey = `fallback_restore_${Date.now()}`;
            const timeoutId = setTimeout(() => {
                // 仍在等待补齐，执行强制恢复
                if (this.currentAnimationPhase === 'waiting_for_restore') {
                    this.restoreOriginalBlockStates(eventData.blocks);
                    this.currentAnimationPhase = 'idle';
                }
                this.pendingAnimationTasks.delete(fallbackKey);
            }, fallbackDelay);
            this.pendingAnimationTasks.set(fallbackKey, timeoutId);
        });
    }
    
    /**
     * 处理定时补齐事件 - 显示方块，播放上升动画，恢复默认状态
     */
    private handleTimedRestoringEvent(eventData: GameEventData): void {
        if (!eventData.blocks || eventData.blocks.length === 0) {
            console.warn("补齐事件没有方块数据");
            return;
        }
        
        this.currentAnimationPhase = 'restoring';
        
        // 上升动画：分三批次播放，间隔0.1-0.3秒
        const playSequence = this.generateBatchedAnimationSequence(eventData.blocks, eventData.randomSeed);
        
     
        
        // 播放补齐动画序列
        this.playRestoreAnimationSequence(playSequence, () => {
          
            this.currentAnimationPhase = 'idle';
        });
    }
    
    /**
     * 保存方块原始状态
     */
    private saveOriginalBlockStates(blocks: BrickPartyBlock[]): void {
        blocks.forEach(block => {
            const blockNode = this.blockGrid[block.x]?.[block.y];
            if (blockNode && cc.isValid(blockNode)) {
                const key = `${block.x}_${block.y}`;
                this.originalBlockStates.set(key, {
                    position: cc.v3(blockNode.x, blockNode.y, 0),
                    scale: cc.v3(blockNode.scaleX, blockNode.scaleY, 1),
                    opacity: blockNode.opacity
                });
            }
        });
      
    }
    
    /**
     * 恢复方块原始状态
     */
    private restoreOriginalBlockStates(blocks: BrickPartyBlock[]): void {
        blocks.forEach(block => {
            const blockNode = this.blockGrid[block.x]?.[block.y];
            const key = `${block.x}_${block.y}`;
            const originalState = this.originalBlockStates.get(key);
            
            if (blockNode && cc.isValid(blockNode) && originalState) {
                blockNode.setPosition(originalState.position);
                blockNode.scaleX = originalState.scale.x;
                blockNode.scaleY = originalState.scale.y;
                blockNode.opacity = originalState.opacity;
                blockNode.active = true; // 确保方块可见
            }
        });
       
    }
    
    /**
     * 生成抖动动画序列 - 所有方块同时播放
     */
    private generateShakeAnimationSequence(blocks: BrickPartyBlock[]): Array<{block: BrickPartyBlock, delay: number}> {
        return blocks.map(block => ({
            block: block,
            delay: 0 // 抖动动画无延迟，同时播放
        }));
    }
    
    /**
     * 生成分批次动画序列 - 用于掉落和上升动画
     */
    private generateBatchedAnimationSequence(blocks: BrickPartyBlock[], randomSeed: number): Array<{block: BrickPartyBlock, delay: number}> {
        if (blocks.length === 0) return [];
        
        // 使用随机种子打乱方块顺序
        const rng = this.createSeededRandom(randomSeed);
        const shuffledBlocks = [...blocks];
        this.shuffleArrayWithSeed(shuffledBlocks, rng);
        
        // 将方块平均分为三批次
        const batchSize = Math.ceil(shuffledBlocks.length / 3);
        const batches = [
            shuffledBlocks.slice(0, batchSize),
            shuffledBlocks.slice(batchSize, batchSize * 2),
            shuffledBlocks.slice(batchSize * 2)
        ];
        
        // 为每批次分配延迟时间 (0ms, 100-200ms, 200-300ms)
        const batchDelays = [0, 50 + Math.floor(Math.random() * 100), 100 + Math.floor(Math.random() * 100)];
        const sequence: Array<{block: BrickPartyBlock, delay: number}> = [];
        
        batches.forEach((batch, batchIndex) => {
            const delay = batchDelays[batchIndex];
            batch.forEach(block => {
                sequence.push({
                    block: block,
                    delay: delay
                });
            });
        });
        
        return sequence;
    }
    
    /**
     * 强制恢复抖动方块状态 - 防止红色状态残留
     */
    private forceRestoreShakeBlocks(blocks: BrickPartyBlock[]): void {
        blocks.forEach(block => {
            const blockNode = this.blockGrid[block.x]?.[block.y];
            const key = `${block.x}_${block.y}`;
            const originalState = this.originalBlockStates.get(key);
            
            if (blockNode && cc.isValid(blockNode) && originalState) {
                // 立即恢复原始状态
                blockNode.setPosition(originalState.position);
                blockNode.scaleX = originalState.scale.x;
                blockNode.scaleY = originalState.scale.y;
                blockNode.opacity = originalState.opacity;
                blockNode.active = true;
                
                // 重置动画状态
                if (this.blockAnimationStates[block.x] && this.blockAnimationStates[block.x][block.y]) {
                    this.blockAnimationStates[block.x][block.y] = BlockAnimationState.NONE;
                }
                if (this.blockAnimationTimers[block.x] && this.blockAnimationTimers[block.x][block.y]) {
                    this.blockAnimationTimers[block.x][block.y] = 0;
                }
                
               
            }
        });
        
        // 清理原始状态数据
        blocks.forEach(block => {
            const key = `${block.x}_${block.y}`;
            this.originalBlockStates.delete(key);
        });
        
       
    }
    
    /**
     * 播放定时动画序列
     */
    private playTimedAnimationSequence(sequence: Array<{block: BrickPartyBlock, delay: number}>, animationType: string, onComplete?: () => void): void {
        let completedCount = 0;
        const totalCount = sequence.length;
        
        if (totalCount === 0) {
            onComplete?.();
            return;
        }
        
        sequence.forEach((item) => {
            const taskKey = `${animationType}_${item.block.x}_${item.block.y}_${Date.now()}`;
            const timeoutId = setTimeout(() => {
                this.playBlockAnimationSafely(item.block.x, item.block.y, animationType);
                
                // 为抖动动画添加额外的状态清理定时器
                if (animationType === BlockAnimationState.SHAKE) {
                    const cleanupKey = `cleanup_${item.block.x}_${item.block.y}_${Date.now()}`;
                    const cleanupTimeout = setTimeout(() => {
                        this.forceResetBlockState(item.block.x, item.block.y);
                        this.pendingAnimationTasks.delete(cleanupKey);
                    }, 1800); // 1.8秒后强制清理状态
                    this.pendingAnimationTasks.set(cleanupKey, cleanupTimeout);
                }
                
                completedCount++;
                if (completedCount === totalCount && onComplete) {
                    onComplete();
                }
                
                this.pendingAnimationTasks.delete(taskKey);
            }, item.delay);
            
            this.pendingAnimationTasks.set(taskKey, timeoutId);
        });
    }
    
    /**
     * 强制重置单个方块状态
     */
    private forceResetBlockState(gridX: number, gridY: number): void {
        const blockNode = this.blockGrid[gridX]?.[gridY];
        const key = `${gridX}_${gridY}`;
        const originalState = this.originalBlockStates.get(key);
        
        if (blockNode && cc.isValid(blockNode)) {
            // 重置动画状态
            if (this.blockAnimationStates[gridX] && this.blockAnimationStates[gridX][gridY]) {
                this.blockAnimationStates[gridX][gridY] = BlockAnimationState.NONE;
            }
            if (this.blockAnimationTimers[gridX] && this.blockAnimationTimers[gridX][gridY]) {
                this.blockAnimationTimers[gridX][gridY] = 0;
            }
            
            // 如果有原始状态，恢复它
            if (originalState) {
                blockNode.setPosition(originalState.position);
                blockNode.scaleX = originalState.scale.x;
                blockNode.scaleY = originalState.scale.y;
                blockNode.opacity = originalState.opacity;
                blockNode.active = true;
                // 同步复位骨骼到Setup Pose，避免动画对插槽可见性/附件的影响残留
                const sk = blockNode.getComponent(sp.Skeleton);
                if (sk) {
                    try {
                        sk.clearTracks();
                        sk.setToSetupPose();
                    } catch (_e) {}
                }
            }
            
           
        }
    }
    
    /**
     * 播放掉落动画序列 - 包含隐藏逻辑
     */
    private playFallAnimationSequence(sequence: Array<{block: BrickPartyBlock, delay: number}>, onComplete?: () => void): void {
        let completedCount = 0;
        const totalCount = sequence.length;
        
        if (totalCount === 0) {
            onComplete?.();
            return;
        }
        
        sequence.forEach((item) => {
            const taskKey = `fall_${item.block.x}_${item.block.y}_${Date.now()}`;
            const timeoutId = setTimeout(() => {
                const blockNode = this.blockGrid[item.block.x]?.[item.block.y];
                if (blockNode && cc.isValid(blockNode)) {
                    // 播放掉落动画（隐藏效果由动画本身控制，不再手动隐藏）
                    this.playBlockAnimationSafely(item.block.x, item.block.y, BlockAnimationState.FALL);
                    
                    // 为防止下落动画结束到上升动画开始之间短暂显示，0.5s 后强制隐藏该格子
                    const hideKey = `fall_hide_${item.block.x}_${item.block.y}_${Date.now()}`;
                    const hideTimeoutId = setTimeout(() => {
                        // 仅当节点仍有效且当前阶段仍为掉落或等待补齐时才隐藏
                        const nodeStillValid = this.blockGrid[item.block.x] && cc.isValid(this.blockGrid[item.block.x][item.block.y]);
                        const stillInFallOrWaiting = (this.currentAnimationPhase === 'falling' || this.currentAnimationPhase === 'waiting_for_restore');
                        if (nodeStillValid && stillInFallOrWaiting) {
                            const n = this.blockGrid[item.block.x][item.block.y];
                            if (n && cc.isValid(n)) n.active = false;
                        }
                        this.pendingAnimationTasks.delete(hideKey);
                    }, 500); // 下落动画单次时长约0.5s
                    this.pendingAnimationTasks.set(hideKey, hideTimeoutId);
                    
                    // 直接统计完成数量
                    completedCount++;
                    if (completedCount === totalCount && onComplete) {
                        onComplete();
                    }
                }
                
                this.pendingAnimationTasks.delete(taskKey);
            }, item.delay);
            
            this.pendingAnimationTasks.set(taskKey, timeoutId);
        });
    }
    
    /**
     * 播放补齐动画序列 - 包含显示和恢复逻辑
     */
    private playRestoreAnimationSequence(sequence: Array<{block: BrickPartyBlock, delay: number}>, onComplete?: () => void): void {
        let completedCount = 0;
        const totalCount = sequence.length;
        
        if (totalCount === 0) {
            onComplete?.();
            return;
        }
        
        sequence.forEach((item) => {
            const taskKey = `restore_${item.block.x}_${item.block.y}_${Date.now()}`;
            const timeoutId = setTimeout(() => {
                const blockNode = this.blockGrid[item.block.x]?.[item.block.y];
                if (blockNode && cc.isValid(blockNode)) {
                    // 显示方块
                    blockNode.active = true;
                    
                    // 播放上升动画
                    this.playBlockAnimationSafely(item.block.x, item.block.y, BlockAnimationState.RISE);
                    
                    // 0.5秒后恢复原始状态
                    setTimeout(() => {
                        const key = `${item.block.x}_${item.block.y}`;
                        const originalState = this.originalBlockStates.get(key);
                        if (blockNode && cc.isValid(blockNode) && originalState) {
                            blockNode.setPosition(originalState.position);
                            blockNode.scaleX = originalState.scale.x;
                            blockNode.scaleY = originalState.scale.y;
                            blockNode.opacity = originalState.opacity;
                            
                        }
                        
                        completedCount++;
                        if (completedCount === totalCount && onComplete) {
                            // 清理所有原始状态数据
                            sequence.forEach(seqItem => {
                                const seqKey = `${seqItem.block.x}_${seqItem.block.y}`;
                                this.originalBlockStates.delete(seqKey);
                            });
                            onComplete();
                        }
                    }, 500); // 上升动画持续0.5秒
                }
                
                this.pendingAnimationTasks.delete(taskKey);
            }, item.delay);
            
            this.pendingAnimationTasks.set(taskKey, timeoutId);
        });
    }
    
    /**
     * 直接播放上升动画（不经过下落）
     */
    private playDirectRiseAnimation(gridX: number, gridY: number): void {
        // 使用安全的动画播放方法
        this.playBlockAnimationSafely(gridX, gridY, BlockAnimationState.RISE);
    }
    
    /**
     * 直接播放上升动画序列（用于补齐事件）
     */
    private playDirectRiseAnimationSequence(sequence: Array<{block: BrickPartyBlock, delay: number}>): void {
        let cumulativeDelay = 0;
        
        sequence.forEach((item, index) => {
            cumulativeDelay += item.delay;
            
            // 延迟播放上升动画
            setTimeout(() => {
                this.playDirectRiseAnimation(item.block.x, item.block.y);
            }, cumulativeDelay);
        });
    }
    
    /**
     * 生成方块动画播放序列
     * 震动：同时播放
     * 下落/补齐：分三批次播放，每批次间隔0.1-0.3s
     */
    private generateAnimationSequence(blocks: BrickPartyBlock[], randomSeed: number, animationType: string): Array<{block: BrickPartyBlock, delay: number}> {
        if (animationType === BlockAnimationState.SHAKE) {
            // 震动动画：所有方块同时播放
            const sequence = blocks.map(block => ({
                block: block,
                delay: 0
            }));
           
            return sequence;
        } else {
            // 下落/补齐动画：分三批次播放
            return this.generateBatchedSequence(blocks, randomSeed);
        }
    }
    
    /**
     * 生成分批次播放序列（用于下落和补齐动画）
     */
    private generateBatchedSequence(blocks: BrickPartyBlock[], randomSeed: number): Array<{block: BrickPartyBlock, delay: number}> {
        if (blocks.length === 0) return [];
        
        // 使用随机种子打乱方块顺序
        const rng = this.createSeededRandom(randomSeed);
        const shuffledBlocks = [...blocks];
        this.shuffleArrayWithSeed(shuffledBlocks, rng);
        
        // 将方块平均分为三批次
        const batchSize = Math.ceil(shuffledBlocks.length / 3);
        const batches = [
            shuffledBlocks.slice(0, batchSize),
            shuffledBlocks.slice(batchSize, batchSize * 2),
            shuffledBlocks.slice(batchSize * 2)
        ];
        
        // 为每批次分配延迟时间 (0.1-0.3s间隔)
        const batchDelays = [0, 0, 0]; // 0ms, 100ms, 200ms
        const sequence: Array<{block: BrickPartyBlock, delay: number}> = [];
        
        batches.forEach((batch, batchIndex) => {
            const delay = batchDelays[batchIndex];
            batch.forEach(block => {
                sequence.push({
                    block: block,
                    delay: delay
                });
            });
        });
        
       
        
        return sequence;
    }
    
    /**
     * 创建基于种子的随机数生成器
     */
    private createSeededRandom(seed: number): () => number {
        let state = seed;
        return function() {
            state = (state * 1664525 + 1013904223) % Math.pow(2, 32);
            return state / Math.pow(2, 32);
        };
    }

    /**
     * 使用给定随机源对数组进行原地洗牌
     */
    private shuffleArrayWithSeed<T>(arr: T[], rng: () => number): void {
        for (let i = arr.length - 1; i > 0; i--) {
            const j = Math.floor(rng() * (i + 1));
            const tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }
    }
    
    // ===== 方块皮肤切换（支持静默） =====
    /**
     * 普通方式切换皮肤（可见）
     */
    public setBlockSkin(skinName: string): void {
        this.setBlockSkinInternal(skinName, false);
    }

    /**
     * 静默切换皮肤（容器先隐藏，一次性切换后再显示）
     */
    public setBlockSkinSilently(skinName: string): void {
        this.setBlockSkinInternal(skinName, true);
    }

    private setBlockSkinInternal(skinName: string, silent: boolean): void {
        // 刷新引用，确保blockGrid可用
        try {
            // @ts-ignore 兼容公开封装
            if (typeof (this as any).refreshBlockReferences === 'function') {
                // @ts-ignore
                (this as any).refreshBlockReferences();
            } else {
                this.refreshBlockGridReferences();
            }
        } catch (_e) {}

        if (silent) this.setBlocksOpacity(0);

        // 保存当前皮肤名称，用于后续重新应用
        this.currentSkinName = skinName;

        // 检查是否有方块的骨骼动画资源还未准备好
        let hasUnreadyBlocks = false;
        let totalBlocks = 0;
        let readyBlocks = 0;

        for (let x = 0; x < this.GRID_SIZE; x++) {
            for (let y = 0; y < this.GRID_SIZE; y++) {
                const blockNode = this.blockGrid[x] && this.blockGrid[x][y];
                if (!blockNode || !cc.isValid(blockNode)) continue;
                
                totalBlocks++;
                const skeletonNode = blockNode.getChildByName('donghua') || blockNode;
                const skeleton = skeletonNode.getComponent(sp.Skeleton);
                if (!skeleton) continue;

                // 检查骨骼数据是否准备好
                if (!skeleton.skeletonData) {
                    hasUnreadyBlocks = true;
                    continue;
                }

                readyBlocks++;
                try {
                    // 只在第一个方块上打印详细调试信息，避免日志过多
                    if (x === 0 && y === 0) {
                        
                        // 尝试获取皮肤信息
                        try {
                            // @ts-ignore - 访问内部属性来获取皮肤信息
                            const internalSkeleton = (skeleton as any)._skeleton;
                            if (internalSkeleton) {
                                const currentSkin = internalSkeleton.skin;
                               
                            }
                        } catch (e) {
                       
                        }
                    }
                    
                    // 设置皮肤
                    skeleton.setSkin(skinName);
                    skeleton.setToSetupPose();
                    
                    // 只在第一个方块上验证结果
                    if (x === 0 && y === 0) {
                        try {
                            // @ts-ignore - 访问内部属性来验证皮肤设置
                            const internalSkeleton = (skeleton as any)._skeleton;
                            if (internalSkeleton) {
                                const newSkin = internalSkeleton.skin;
                                const newSkinName = newSkin ? newSkin.name : 'null';
                             
                                
                                if (newSkinName !== skinName) {
                                    console.warn(`⚠️ 第一个方块皮肤设置失败！期望: ${skinName}, 实际: ${newSkinName}`);
                                } else {
                                  
                                }
                            }
                        } catch (e) {
                            
                        }
                    }
                    
                } catch (e) {
                    cc.warn(`设置方块皮肤失败 (${x},${y}) -> ${skinName}`, e);
                }
            }
        }

       

        // 如果有方块还未准备好，启用重试机制
        if (hasUnreadyBlocks && totalBlocks > 0) {
          
            this.trySetBlockSkinWithRetry(skinName, silent, 0);
        }

        if (silent) this.setBlocksOpacity(255);
    }

    /**
     * 延迟重试设置方块皮肤
     */
    private trySetBlockSkinWithRetry(skinName: string, silent: boolean, retryCount: number): void {
        const maxRetries = 5;
        if (retryCount >= maxRetries) {
            console.warn(`❌ 方块皮肤设置重试失败，已达到最大重试次数: ${maxRetries}`);
            return;
        }

        // 递增延迟：0.1s, 0.2s, 0.3s, 0.4s, 0.5s
        const delayTime = 0.1 + retryCount * 0.1;
        
        setTimeout(() => {
          
            
            let hasUnreadyBlocks = false;
            let totalBlocks = 0;
            let successBlocks = 0;

            for (let x = 0; x < this.GRID_SIZE; x++) {
                for (let y = 0; y < this.GRID_SIZE; y++) {
                    const blockNode = this.blockGrid[x] && this.blockGrid[x][y];
                    if (!blockNode || !cc.isValid(blockNode)) continue;
                    
                    totalBlocks++;
                    const skeletonNode = blockNode.getChildByName('donghua') || blockNode;
                    const skeleton = skeletonNode.getComponent(sp.Skeleton);
                    if (!skeleton) continue;

                    // 检查骨骼数据是否准备好
                    if (!skeleton.skeletonData) {
                        hasUnreadyBlocks = true;
                        continue;
                    }

                    try {
                        skeleton.setSkin(skinName);
                        skeleton.setToSetupPose();
                        successBlocks++;
                    } catch (e) {
                        cc.warn(`重试设置方块皮肤失败 (${x},${y}) -> ${skinName}`, e);
                    }
                }
            }

            

            // 如果还有方块未准备好，继续重试
            if (hasUnreadyBlocks && retryCount < maxRetries - 1) {
                this.trySetBlockSkinWithRetry(skinName, silent, retryCount + 1);
            } else if (successBlocks > 0) {
               
            }
        }, delayTime * 1000);
    }

    /**
     * 公共：设置方块父节点透明度（0-255）
     */
    public setBlocksOpacity(opacity: number): void {
        if (!this.blockParent || !cc.isValid(this.blockParent)) return;
        // Creator 2.4 无 UIOpacity 组件，直接使用节点 opacity（会级联到子节点）
        this.blockParent.opacity = opacity;
    }

    /**
     * 按序列播放动画
     */
    private playAnimationSequence(sequence: Array<{block: BrickPartyBlock, delay: number}>, animationState: string): void {
        sequence.forEach((item, index) => {
            const taskKey = `${item.block.x}-${item.block.y}-${animationState}-${Date.now()}-${index}`;
            
            // 直接使用每个方块的延迟时间，不累加
            const timeoutId = setTimeout(() => {
                // 从待执行任务中移除
                this.pendingAnimationTasks.delete(taskKey);
                // 执行动画前再次验证节点是否存在
                this.playBlockAnimationSafely(item.block.x, item.block.y, animationState);
            }, item.delay);
            
            // 记录待执行的任务，以便需要时可以取消
            this.pendingAnimationTasks.set(taskKey, timeoutId);
        });
    }
    
    /**
     * 安全播放方块动画 - 带有额外的验证和错误处理
     */
    private playBlockAnimationSafely(gridX: number, gridY: number, animationState: string): void {
       
        
        // 验证网格坐标
        if (!this.isValidGridPosition(gridX, gridY)) {
            console.warn(`无效的网格坐标: (${gridX}, ${gridY})`);
            return;
        }

        // 刷新方块网格引用 - 重新扫描父节点中的方块
        this.refreshBlockGridReferences();
        
        const blockNode = this.blockGrid[gridX][gridY];
        if (!blockNode || !cc.isValid(blockNode)) {
            console.warn(`方块节点不存在或已销毁: (${gridX}, ${gridY})，跳过动画`);
            return;
        }
        
        // 验证节点是否仍在场景树中
        if (!blockNode.parent || !blockNode.activeInHierarchy) {
            console.warn(`方块节点不在活跃状态: (${gridX}, ${gridY})，跳过动画`);
            return;
        }
        
        try {
            // 设置动画状态
            this.blockAnimationStates[gridX][gridY] = animationState;
            this.setBlockAnimationState(blockNode, animationState);
            
            const duration = this.ANIMATION_DURATIONS[animationState] || 500;
            this.blockAnimationTimers[gridX][gridY] = Date.now() + duration;
            
            // 动画结束后重置为默认状态
            const resetTaskKey = `reset-${gridX}-${gridY}-${Date.now()}`;
            const resetTimeoutId = setTimeout(() => {
                this.pendingAnimationTasks.delete(resetTaskKey);
                // 再次验证节点存在性
                if (this.blockGrid[gridX][gridY] && cc.isValid(this.blockGrid[gridX][gridY]) && 
                    this.blockAnimationStates[gridX][gridY] === animationState) {
                    this.blockAnimationStates[gridX][gridY] = BlockAnimationState.NONE;
                    this.setBlockAnimationState(this.blockGrid[gridX][gridY], BlockAnimationState.NONE);
                    this.blockAnimationTimers[gridX][gridY] = 0;
                }
            }, duration);
            
            this.pendingAnimationTasks.set(resetTaskKey, resetTimeoutId);
            
        } catch (error) {
            console.error(`播放方块动画时发生错误: (${gridX}, ${gridY})`, error);
        }
    }

    /**
     * 播放单个方块动画 (保留原方法用于向后兼容)
     */
    private playBlockAnimation(gridX: number, gridY: number, animationState: string): void {
        this.playBlockAnimationSafely(gridX, gridY, animationState);
    }
    
    /**
     * 设置方块的骨骼动画状态
     */
    private setBlockAnimationState(blockNode: cc.Node, animationState: string): void {
        // 查找骨骼动画组件
        const skeletonComponent = blockNode.getComponent(sp.Skeleton);
        if (!skeletonComponent) {
            console.warn(`方块节点 ${blockNode.name} 没有骨骼动画组件`);
            return;
        }
        
        try {
            if (animationState === BlockAnimationState.NONE) {
                // NONE状态：停止播放动画，回到默认状态
                skeletonComponent.clearTracks();
                // 关键：复位到Setup Pose，避免皮肤在动画后保持插槽透明/空附件
                skeletonComponent.setToSetupPose();
                
                // 重新应用当前皮肤，因为setToSetupPose可能会重置皮肤
                if (this.currentSkinName && this.currentSkinName !== 'zhuankuai1') {
                    try {
                        skeletonComponent.setSkin(this.currentSkinName);
                        
                    } catch (e) {
                        console.warn(`重新应用皮肤失败: ${this.currentSkinName}`, e);
                    }
                }
               
            } else {
                // 根据动画类型设置循环模式
                const shouldLoop = animationState === BlockAnimationState.SHAKE; // 只有抖动动画循环播放
                
                // 播放对应的骨骼动画
                skeletonComponent.setAnimation(0, animationState, shouldLoop);
               
            }
        } catch (error) {
            console.error(`播放骨骼动画失败: ${error}`);
        }
    }
    
    /**
     * 获取指定位置的方块节点
     */
    public getBlockNode(gridX: number, gridY: number): cc.Node {
        if (gridX < 0 || gridX >= this.GRID_SIZE || gridY < 0 || gridY >= this.GRID_SIZE) {
            return null;
        }
        return this.blockGrid[gridX][gridY];
    }
    
    /**
     * 获取指定位置的动画状态
     */
    public getBlockAnimationState(gridX: number, gridY: number): string {
        if (gridX < 0 || gridX >= this.GRID_SIZE || gridY < 0 || gridY >= this.GRID_SIZE) {
            return BlockAnimationState.NONE;
        }
        return this.blockAnimationStates[gridX][gridY];
    }
    
    /**
     * 强制停止所有动画
     */
    public stopAllAnimations(): void {
        // 首先取消所有待执行的动画任务
        this.cancelAllPendingAnimations();
        
        for (let x = 0; x < this.GRID_SIZE; x++) {
            for (let y = 0; y < this.GRID_SIZE; y++) {
                const blockNode = this.blockGrid[x][y];
                if (blockNode && cc.isValid(blockNode)) {
                    // 强制清空所有动画轨道并恢复到默认状态
                    this.clearAllSkeletonTracks(blockNode);
                    this.blockAnimationStates[x][y] = BlockAnimationState.NONE;
                    this.blockAnimationTimers[x][y] = 0;
                    
                    // 恢复方块的可见性（修复上一把隐藏的方块在新游戏中仍然隐藏的问题）
                    blockNode.active = true;
                }
            }
        }
    }

    /**
     * 清空节点上所有骨骼动画轨道，恢复到默认状态
     */
    private clearAllSkeletonTracks(blockNode: cc.Node): void {
        try {
            // 查找骨骼动画组件
            const skeletonComponent = blockNode.getComponent(sp.Skeleton);
            if (!skeletonComponent) {
                console.warn(`方块节点 ${blockNode.name} 没有骨骼动画组件`);
                return;
            }
            
            // 游戏结束或第二局游戏开始前，清理上一局的游戏数据
            // 1. 清空所有动画轨道，停止所有动画
            skeletonComponent.clearTracks();
            
            // 2. 将骨骼和插槽重置到初始姿势
            skeletonComponent.setToSetupPose();
            
           
            
        } catch (error) {
            console.error(`清空骨骼动画轨道失败: ${error}`);
        }
    }
    
    /**
     * 清理资源
     */
    public cleanup(): void {
        this.stopAllAnimations();
        
        // 重置所有方块节点状态（不销毁，因为它们是场景中预先创建的）
        for (let x = 0; x < this.GRID_SIZE; x++) {
            for (let y = 0; y < this.GRID_SIZE; y++) {
                const blockNode = this.blockGrid[x][y];
                if (blockNode && cc.isValid(blockNode)) {
                    this.setBlockAnimationState(blockNode, BlockAnimationState.NONE);
                }
            }
        }
        
        // 清空数组
        this.blockGrid = [];
        this.blockAnimationStates = [];
        this.blockAnimationTimers = [];
        
        // 确保清理待执行任务映射
        this.pendingAnimationTasks.clear();
        
     
    }
    
    /**
     * 添加公共方法用于外部调用刷新方块引用
     */
    public refreshBlockReferences(): void {
        this.refreshBlockGridReferences();
    }
    
    /**
     * 断线重连时直接隐藏指定方块（不播放动画）
     * @param gridX 网格 X 坐标
     * @param gridY 网格 Y 坐标
     */
    public hideBlockDirectly(gridX: number, gridY: number): void {
        if (!this.isValidGridPosition(gridX, gridY)) {
            console.warn(`无效的网格坐标: (${gridX}, ${gridY})`);
            return;
        }
        
        const blockNode = this.blockGrid[gridX][gridY];
        if (blockNode && cc.isValid(blockNode)) {
            // 直接隐藏方块，不播放动画
            blockNode.active = false;
            
            // 兜底：断线重连场景下，可能不会收到后续的补齐事件，导致方块长期保持隐藏
            // 这里设置一个不加入 pendingAnimationTasks 的超时恢复，避免被 cancelAllPendingAnimations() 清掉
            try {
                const SAFE_RESTORE_DELAY_MS = 3000; // 掉落阶段2s + 缓冲
                setTimeout(() => {
                    // 仍存在、仍有效、仍处于隐藏，且当前不在补齐阶段时，强制恢复显示
                    const stillValid = this.blockGrid[gridX] && cc.isValid(this.blockGrid[gridX][gridY]);
                    const stillHidden = stillValid && this.blockGrid[gridX][gridY] && !this.blockGrid[gridX][gridY].active;
                    const notRestoring = this.currentAnimationPhase !== 'restoring';
                    if (stillHidden && notRestoring) {
                        const n = this.blockGrid[gridX][gridY];
                        if (n && cc.isValid(n)) {
                            n.active = true;
                            // 同步清理骨骼轨道，避免隐藏状态期间的插槽可见性残留
                            const sk = n.getComponent(sp.Skeleton);
                            if (sk) {
                                try {
                                    sk.clearTracks();
                                    sk.setToSetupPose();
                                } catch (_e) {}
                            }
                        }
                    }
                }, SAFE_RESTORE_DELAY_MS);
            } catch (_e) {}
            
        } else {
            console.warn(`方块节点不存在: (${gridX}, ${gridY})`);
        }
    }
    
    /**
     * 断线重连时直接显示指定方块（不播放动画）
     * @param gridX 网格 X 坐标
     * @param gridY 网格 Y 坐标
     */
    public showBlockDirectly(gridX: number, gridY: number): void {
        if (!this.isValidGridPosition(gridX, gridY)) {
            console.warn(`无效的网格坐标: (${gridX}, ${gridY})`);
            return;
        }
        
        const blockNode = this.blockGrid[gridX][gridY];
        if (blockNode && cc.isValid(blockNode)) {
            // 直接显示方块，不播放动画
            blockNode.active = true;
            
            // 确保方块处于默认状态（清除任何动画效果）
            this.setBlockAnimationState(blockNode, BlockAnimationState.NONE);
            this.blockAnimationStates[gridX][gridY] = BlockAnimationState.NONE;
            this.blockAnimationTimers[gridX][gridY] = 0;
            
           
        } else {
            console.warn(`方块节点不存在: (${gridX}, ${gridY})`);
        }
    }
}
